/******************************************************************************
 * Copyright (C) 2015  671643387@qq.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *****************************************************************************/

#ifndef NET_TCPSERVER_H_
#define NET_TCPSERVER_H_

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif

#include <string>
#include <boost/scoped_ptr.hpp>
#include <boost/scoped_array.hpp>
#include <boost/unordered_map.hpp>
#include "Ucop/System/Mutex.h"
#include "Ucop/Net/TcpSocket.h"
#include "Ucop/Net/TcpListener.h"
#include "Ucop/Net/TcpRunnable.h"
#include "Ucop/Net/TcpConnectionFactory.h"


namespace Ucop {
namespace Net {

        class TcpServer
        {
        public:
            /* Max worker number */
            const static int MAX_WORKERS = 0x80;

            TcpServer(TcpConnectionFactory *_ConnFactory = NULL);
            ~TcpServer(void);

            void SetConnectionFactory(TcpConnectionFactory *_ConnFactory);

            bool Start(const char *_Host, int _Port, int _Backlog, int _AddWorkerNum = 0);
            void Stop(void);
            void Join(void);

            void CloseListener(void) { _Mylistener->Close(); }

            int GetErrorCode(void) const { return _MyerrorCode; }
            const std::string& GetErrorString(void) const { return _MyerrorString; }

        private:
            friend class TcpSocket;

            void _Uninitialize(void);
            void _GenErrorInfo(void);
            void _CloseSocket(TcpSocket *_Sock);
            bool _CreateAddtionalWorkers(int _AddWorkerNum);
            void _StopAddtionalWorkers(void);
            void _CloseAddtionalWorkers(void);
            void _DoAccept(evutil_socket_t, struct sockaddr *, int, void *);
            TcpRunnable *_FindWorker(void);

            static void _OnAccept(evutil_socket_t, struct sockaddr *, int, void *);
            

            boost::scoped_ptr<TcpListener> _Mylistener;
            typedef boost::unordered_map<int, TcpSocket*>   SocketMap;
            volatile int _MyconnidGen;
            SocketMap _Myconnections;
            System::Mutex _MyconnectionsLock;
            boost::scoped_ptr<TcpConnectionFactory> _Myconnf;
            TcpRunnable _MymainWorker;
            int _MyaddtionalWorkerNum;
            boost::scoped_array<TcpRunnable*> _MyaddtionalWorkers;
            int _MyerrorCode;
            std::string _MyerrorString;
        };

    }
}

#endif // NET_TCPSERVER_H_
